iT邦幫忙

2022 iThome 鐵人賽

DAY 5
0
Modern Web

擁抱 .Net Core系列 第 5

[Day5] .Net Core 中的相依性注入 - 2

  • 分享至 

  • xImage
  •  

讓我們回頭看看服務存留期吧

先複習一下

  • ServiceDescriptor => 描述服務如何以及對應實體取得的物件
  • IServiceCollection => ServiceDescriptor 的集合
  • IServiceProvider => 服務實際的提供者

IServiceScope

我們前面提到了在.Net Core 中 Lifetime 被註冊為 Scoped 在每個Request 中會拿到相同的Instance
那要怎麼做到這件事呢,就需要有一個控制生命週期的物件IServiceScope

每個 IServiceScope 中會有一個 IServiceProviderIServiceScope 會負責管理自己所有 IServiceProvider的生命週期。

這邊來看個圖吧
.Net Core的應用程式啟動後會生成一個IServicePovider,後面姑且稱呼他為Root
可以看見每個Request都會建立一個IServiceScope
https://ithelp.ithome.com.tw/upload/images/20220916/20109549zIYNGNevxw.png

可以透過IServiceProvider.CreateScope來產生一個IServiceScope

var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISingletonService, SingletonService>();
serviceCollection.AddScoped<IScopedService, ScopedService>();
serviceCollection.AddTransient<ITransientService, TransientService>();
var serviceProvider = serviceCollection.BuildServiceProvider();

IServiceScope serviceScope = serviceProvider.CreateScope();

有了Scope的概念之後,我們來看看生命週期是如何管理的吧

服務留存期管理

IServiceProver 在解析完服務並取出執行個體,會將服務放在一個名為RealizedServicesConcurrentDictionary ,當這個服務實作了IDisposeIAsyncDisposable 時他會被另外加到Disposable Services 的清單中。

public interface IService{}
public class Service : IService{}

public interface IDisposableService{}
public class DisposableService : IDisposableService, IDisposable
{
    public void Dispose()
    {
    }
}

當我們解析或注入時,執行個體會被放到對應的清單
https://ithelp.ithome.com.tw/upload/images/20220916/20109549HLh7chxKVh.png

而當 IServiceScope 的實例被Dispose的時候,會呼叫ServiceProviderDispose() 方法,並依序呼叫
Disposable Services中的Instance的Dispose()

我們回過頭來看當我們要求/注入三種不同生命週期時服務是怎麼被處裡的

Singleton

如果RootRealizedServices中有對應的執行個體,那就會取該執行個體。沒有的話就新增一個執行個體並放到
RootRealizedServices,有實現IDisposable,會另外再放到Disposable Services

Scoped

如果當前Scope的IServiceProviderRealizedServices中有對應的執行個體,那就會取該執行個體。沒有的話就新增一個執行個體並放到
當前Scope的IServiceProviderRealizedServices,有實現IDisposable,會另外再放到Disposable Services)

transient

管他有沒有,新增一個執行個體就對了

小實驗

program.cs

var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISingletonService, SingletonService>();
serviceCollection.AddScoped<IScopedService, ScopedService>();
serviceCollection.AddTransient<ITransientService, TransientService>();
var root = serviceCollection.BuildServiceProvider();
var childScope = root.CreateScope();
var childProvider = childScope.ServiceProvider;
var descendantScope = childProvider.CreateScope();
var descendantProvider = descendantScope.ServiceProvider;

var descendantSingletonService = descendantProvider.GetService<ISingletonService>();
var descendantScopedService = descendantProvider.GetService<IScopedService>();
var childSingletonService = childProvider.GetService<ISingletonService>();
var childScopedService = childProvider.GetService<IScopedService>();
var rootSingletonService = root.GetService<ISingletonService>();
var rootScopedService = root.GetService<IScopedService>();

Console.WriteLine("Root Singleton Service: " + rootSingletonService.Id);
Console.WriteLine("Root Scoped Service: " + rootScopedService.Id);
Console.WriteLine("Child Singleton Service: " + childSingletonService.Id);
Console.WriteLine("Child Scoped Service: " + childScopedService.Id);
Console.WriteLine("Descendant Singleton Service: " + descendantSingletonService.Id);
Console.WriteLine("Descendant Scoped Service: " + descendantScopedService.Id);

結構圖:
https://ithelp.ithome.com.tw/upload/images/20220916/20109549qDBAEpOKRt.png

執行結果:
https://ithelp.ithome.com.tw/upload/images/20220916/201095491kkvQkFkR5.png

可以看見所有的SingletonService 都是同一個,不同Scope的ScopeService是不同的

.Net Core 中的相依性注入實作概念

先發文我慢慢補 0.0b
補在[Day9] 補坑之談談 .Net core 的相依性注入實作


上一篇
[Day4] .Net Core 中的相依性注入 - 1
下一篇
[Day6] 泛型主機(Host) - 1
系列文
擁抱 .Net Core30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言